package org.zxt.web.context;

import org.zxt.web.nio.IHTTPSession;

import java.util.*;

public class Router<V> {
    private Map<String, Router<V>> absRouter; // ** ->  user ->
    private Map.Entry<String, Router<V>> matchRouter;
    private String route; // api | **
    private V value;

    public V put(String path, V handler) {
        if(path.startsWith("/")){
            path = path.substring(1);
        }
        int pos = path.indexOf("/");
        if(pos != -1){
            String prefix = path.substring(0, pos);
            String substr = path.substring(pos+1);
            Router<V> handlerRouter = null;
            if(prefix.startsWith(":")){
                handlerRouter = new Router<>();
                this.matchRouter = new AbstractMap.SimpleEntry<>(prefix, handlerRouter);
            } else {
                if(this.absRouter == null){
                    this.absRouter = new TreeMap<>();
                }
                handlerRouter = absRouter.computeIfAbsent(prefix, (k)-> new Router<>());
            }
            this.route = prefix;
            return handlerRouter.put(substr, handler);
        } else {
            if(path.equals("")){
                V old = this.value;
                this.route = path;
                this.value = handler;
                return old;
            } else if (path.contains("/")){
               return this.put(path, handler);
            } else if (path.startsWith(":")){
                V old = this.value;
//                if(this.matchRouter != null){
//                    old = this.matchRouter.getValue().value;
//                }
//                Router<V> router = new Router<>();
//                router.value = handler;
//                router.route = path;
//                this.matchRouter = new AbstractMap.SimpleEntry<>(path, router);
                this.route = path;
                this.value = handler;
                return old;
            } else {
                if (this.absRouter == null){
                    this.absRouter = new TreeMap<>();
                }
                Router<V> router = this.absRouter.get(path);
                if(router != null){
                    V old = router.value;
                    router.value = handler;
                    return old;
                } else {
                    router = new Router<>();
                    router.value = handler;
                    router.route = path;
                    this.absRouter.put(path, router);
                    return null;
                }
            }
        }
    }

    public V get(IHTTPSession session, String path) {
        if(this.route == null){
            return null;
        }
        if(path.startsWith("/")){
            path = path.substring(1);
        }
        int pos = path.indexOf("/");
        if(pos != -1){
            String prefix = path.substring(0, pos);
            String substr = path.substring(pos + 1);
            if(this.route.startsWith(":")) {
                List<String> pval = session.getParameters().computeIfAbsent("__PATH:" + this.route.substring(1), k->new ArrayList<>(1));
                pval.add(prefix);
                if(this.matchRouter == null){
                    return null;
                }
                return this.matchRouter.getValue().get(session, substr);
            } else {
                if(this.absRouter == null){
                    return null;
                }
                Router<V> router = this.absRouter.get(prefix);
                return router == null ? this.value : router.get(session, substr);
            }
        } else {
            if(this.route.startsWith(":")){
                List<String> pval = session.getParameters().computeIfAbsent("__PATH:"+this.route.substring(1), k->new ArrayList<>(1));
                pval.add(path);
                return this.value;
            } else if(this.route.equals(path)){
                return this.value;
            } else {
                Router<V> router = this.absRouter.get(path);
                return router == null ? this.value : router.value;
            }
        }
    }

}
